package org.airmvc
{
	import flash.display.DisplayObject;
	import flash.display.Stage;
	import flash.utils.Dictionary;
	
	/**
	 * 消息分派器
	 * @author WLDragon
	 */
	public class Dispatcher
	{
		
		public function Dispatcher()
		{
			newsMap = new Dictionary();
		}
		
		/**
		 * 广播消息
		 * @param	news 消息名
		 * @param	args 参数列表，在执行处理函数时总会把消息名作为最后一个参数，可以通过arguments[arguments.length - 1]来获得消息名
		 */
		public function broadcast(news:String, args:Array):void
		{
			var handlers:Array = newsMap[news];
			if (handlers != null)
			{
				//循环执行监听该类型事件的所有处理函数
				for each (var h:Function in handlers)
				{
					h.apply(null, args);
				}
				
				handlers = null;
			}
		}
		
		/**
		 * 关注某消息
		 * @param	news    被关注的消息名
		 * @param	handler 处理该消息的函数
		 */
		public function interest(news:String, handler:Function):void
		{
			var handlers:Array = newsMap[news];
			if (handlers == null)
			{
				handlers = [];
				newsMap[news] = handlers;
			}
			if (handlers.indexOf(handler) > -1)
			{
				//已经存在该事件的处理函数,不重复添加
				return;
			}
			handlers.push(handler);
			handler = null;
		}
		
		/**
		 * 查询该消息是否有被关注
		 * @param	news 消息名
		 * @return
		 */
		public function hasNews(news:String):Boolean
		{
			var handlers:Array = newsMap[news];
			return (handlers != null && handlers.length > 0);
		}
		
		/**
		 * 取消对消息的关注
		 * @param	news    消息名
		 * @param	handler 对应的处理函数，若为null，则取消所有模块对此消息的关注，但在arimvc中暂不开放此功能，尽量保持模块之间相互独立
		 */
		public function cancelInterest(news:String, handler:Function = null):void
		{
			var handlers:Array = newsMap[news];
			if (handlers != null)
			{
				var i:int = handlers.indexOf(handler);
				if (i > -1)
				{
					//删除该处理事件
					handlers.splice(i, 1);
				}
				if (handlers.length == 0)
				{
					//将该类型的侦听从字典里删除
					delete newsMap[news];
				}
				else if (handler == null)
				{
					handlers.length = 0;
					delete newsMap[news];
				}
				
				handler = null;
			}
		}
		
		/**
		 * 模块内发送消息
		 * @param	msg      消息名
		 * @param	source   发送消息显示对象,直接填this
		 * @param	... args 参数
		 */
		static public function send(msg:String, source:DisplayObject, ... args):void
		{
			var p:* = source.parent;
			var v:View = p as View;
			
			//如果source不是View子类的直接子显示对象，则深入寻找View
			while (v == null)
			{
				if (p is Stage)
				{
					throw new Error("祖先容器中必须有一个是View类型！");
				}
				else
				{
					v = p as View;
					p = p.parent;
				}
			} 
			
			var fun:Function = v.messageMap[msg] as Function;
			if(fun)
				fun.apply(null,args);
		}
		
		/**消息收集器*/
		private var newsMap:Dictionary;
	}

}